﻿/*
* Copyright (C) 2020 ~ 2023 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkGb28181.h"
#include "MkGbPtz.h"
#include "MkGbUtil.h"
#include "MkEvent/MkEventPool.h"
#include "MkGbRtsp.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkTime.h"
#include "MkUtil/MkLog.h"
#include <tinyxml2.h>

CMkGb28181::CMkGb28181(CMkEventPool* pEventPool, CMkTimer* pTimer)
    : CMkSipServer(pEventPool, pTimer)
    , m_CheckOffsetMilliSec(1000)
    , m_RequestTimeOutSec(5)
    , m_ReqCb(nullptr)
    //, m_AuthorReqCb(nullptr)
    , m_Sn(1)
    , m_bCheckDstId(TRUE)
{
    m_SupportQueryCmd.emplace_back("DeviceStatus");
    m_SupportQueryCmd.emplace_back("Catalog");
    m_SupportQueryCmd.emplace_back("DeviceInfo");
    m_SupportQueryCmd.emplace_back("RecordInfo");
    m_SupportQueryCmd.emplace_back("ConfigDownload");
    m_SupportQueryCmd.emplace_back("PresetQuery");
    m_SupportQueryCmd.emplace_back("HomePositionQuery");
    m_SupportQueryCmd.emplace_back("CruiseTrackListQuery");
    m_SupportQueryCmd.emplace_back("CruiseTrackQuery");
    m_SupportQueryCmd.emplace_back("PTZPosition");
    m_SupportQueryCmd.emplace_back("SDCardStatus");
    m_SupportQueryCmd.emplace_back("DeviceConfig");
    m_SupportQueryCmd.emplace_back("DeviceControl");
    m_SupportQueryCmd.emplace_back("Alarm");
    m_SupportQueryCmd.emplace_back("MobilePosition");
    m_SupportQueryCmd.emplace_back("MediaStatus");
    m_SupportQueryCmd.emplace_back("Broadcast");
    m_SupportQueryCmd.emplace_back("UploadSnapShotFinished");
    m_SupportQueryCmd.emplace_back("VideoUploadNotify");
    m_SupportQueryCmd.emplace_back("DeviceUpgradeResult");
    m_SupportQueryCmd.emplace_back("Keepalive");
}

Uint32 CMkGb28181::Start(const MkGbStartParam& Param, const MkGbRequestCallback& Cb/*, const MkGbAuthorReqCb& AuthorReqCb*/)
{
    Uint32 ErrorCode = NoneError;
    if (!Cb) {
        return InvalidParams;
    }
    ErrorCode = CMkSipServer::Start(Param.SipId, Param.SipRealm, Param.LocalHost, Param.LocalPort, Param.MappingHost, Param.MappingPort, Param.LocalHost, Param.LocalPort, Param.MappingHost, Param.MappingPort);
    MkCheckErrorLog(ErrorCode, "start mk gb server id:%s on local port(%s:%d) mapping port(%s:%d) failed\n", Param.SipId.c_str(), Param.LocalHost.c_str(), Param.LocalPort, Param.MappingHost.c_str(), Param.MappingPort);

    m_ReqCb = Cb;
    //m_AuthorReqCb = AuthorReqCb;
    m_RegisterExpries = Param.RegisterExpires;
    m_SubscribeExpires = Param.SubscribeExpires;
    m_bCheckDstId = Param.bCheckDstId;
    MkInfoLog("start mk gb server id:%s on local port(%s:%d)  mapping port(%s:%d) success\n", Param.SipId.c_str(), Param.LocalHost.c_str(), Param.LocalPort, Param.MappingHost.c_str(), Param.MappingPort);
#ifdef MkUt
    m_CheckOffsetMilliSec = 0;
#endif
    GetTimer()->AddTimer([this]() {
        DoCheck();
    }, m_CheckOffsetMilliSec, m_CheckTimer);
    return NoneError;
}

Uint32 CMkGb28181::Stop()
{
    GetTimer()->DeleteTimer(m_CheckTimer);
    return CMkSipServer::Stop();
}

Uint32 CMkGb28181::MessageRequest(const CMkGbMessageRequest& Req, const MkGbResponseCallback& ResCb)
{
    MkGbRouter Router;
    Uint32 ErrorCode = GetRouter(Req.m_RouterId, Router);
    MkCheckErrorLog(ErrorCode, "dst id:%s not found\n", Req.m_RouterId.c_str());

    MkVectorString::iterator it = m_SupportQueryCmd.begin();
    for (; it != m_SupportQueryCmd.end(); it++) {
        if (*it == Req.m_CmdType) {
            break;
        }
    }
    if (it == m_SupportQueryCmd.end()) {
        MkErrorLog("input invalid query cmd type:%s\n", Req.m_CmdType.c_str());
        return InvalidParams;
    }
    tinyxml2::XMLDocument doc;
    MkString strSn = std::to_string(m_Sn++);
    MkString strXml;
    doc.InsertFirstChild(doc.NewDeclaration());

    tinyxml2::XMLElement *root = doc.NewElement(Req.m_MessageType.c_str());
    doc.InsertEndChild(root);

    tinyxml2::XMLElement *ItemNode = doc.NewElement("CmdType");
    ItemNode->InsertFirstChild(doc.NewText(Req.m_CmdType.c_str()));
    root->InsertEndChild(ItemNode);

    ItemNode = doc.NewElement("SN");
    ItemNode->InsertFirstChild(doc.NewText(strSn.c_str()));
    root->InsertEndChild(ItemNode);
    if (!Req.m_DeviceId.empty()) {
        ItemNode = doc.NewElement("DeviceID");
        ItemNode->InsertFirstChild(doc.NewText(Req.m_DeviceId.c_str()));
        root->InsertEndChild(ItemNode);
    }
    GbMessageToXml(Req.m_Message, doc, root);

    tinyxml2::XMLPrinter printer;
    doc.Print(&printer);
    strXml = printer.CStr();

    AddRequest(strSn, ResCb);
    return SendSipRequest(Req.m_RouterId, Req.m_DstId, Router.SipRealm, MkSipMethodMessage, Router.RemoteHost, Router.RemotePort, Router.bTcp, nullptr, MkMapString(), MkSipContentXml, strXml);
}

Uint32 CMkGb28181::InviteMessageRequest(const CMkGbMessageRequest& Req, const MkString& CallId, const MkGbResponseCallback& ResCb)
{
    tinyxml2::XMLDocument doc;
    MkString strSn = std::to_string(m_Sn++);
    MkString strXml;
    doc.InsertFirstChild(doc.NewDeclaration());

    tinyxml2::XMLElement *root = doc.NewElement(Req.m_MessageType.c_str());
    doc.InsertEndChild(root);

    tinyxml2::XMLElement *ItemNode = doc.NewElement("CmdType");
    ItemNode->InsertFirstChild(doc.NewText(Req.m_CmdType.c_str()));
    root->InsertEndChild(ItemNode);

    ItemNode = doc.NewElement("SN");
    ItemNode->InsertFirstChild(doc.NewText(strSn.c_str()));
    root->InsertEndChild(ItemNode);
    if (!Req.m_DeviceId.empty()) {
        ItemNode = doc.NewElement("DeviceID");
        ItemNode->InsertFirstChild(doc.NewText(Req.m_DeviceId.c_str()));
        root->InsertEndChild(ItemNode);
    }
    GbMessageToXml(Req.m_Message, doc, root);

    tinyxml2::XMLPrinter printer;
    doc.Print(&printer);
    strXml = printer.CStr();
    Uint32 ErrorCode = CallMessage(CallId, MkSipContentXml, strXml, [this, ResCb](const CMkSipMessage& SipMessage) {
        AddRequest(SipMessage.GetTransactionId(), ResCb);
    });
    return ErrorCode;
}

Uint32 CMkGb28181::SubscribeRequest(const CMkGbSubscribeRequest& Req, const MkGbResponseCallback& ResCb)
{
    MkVectorString::iterator it = m_SupportQueryCmd.begin();
    for (; it != m_SupportQueryCmd.end(); it++) {
        if (*it == Req.m_CmdType) {
            break;
        }
    }
    if (it == m_SupportQueryCmd.end()) {
        MkErrorLog("input invalid query cmd type:%s\n", Req.m_CmdType.c_str());
        return InvalidParams;
    }
    tinyxml2::XMLDocument doc;
    MkString strSn = std::to_string(m_Sn++);
    MkString strXml;
    doc.InsertFirstChild(doc.NewDeclaration());

    tinyxml2::XMLElement *root = doc.NewElement(Req.m_MessageType.c_str());
    doc.InsertEndChild(root);

    tinyxml2::XMLElement *ItemNode = doc.NewElement("CmdType");
    ItemNode->InsertFirstChild(doc.NewText(Req.m_CmdType.c_str()));
    root->InsertEndChild(ItemNode);

    ItemNode = doc.NewElement("SN");
    ItemNode->InsertFirstChild(doc.NewText(strSn.c_str()));
    root->InsertEndChild(ItemNode);
    if (!Req.m_DeviceId.empty()) {
        ItemNode = doc.NewElement("DeviceID");
        ItemNode->InsertFirstChild(doc.NewText(Req.m_DeviceId.c_str()));
        root->InsertEndChild(ItemNode);
    }
    GbMessageToXml(Req.m_Message, doc, root);

    tinyxml2::XMLPrinter printer;
    doc.Print(&printer);
    strXml = printer.CStr();

    MkGbRouter Router;
    Uint32 ErrorCode = GetRouter(Req.m_RouterId, Router);
    MkCheckErrorLog(ErrorCode, "dst id:%s not found\n", Req.m_RouterId.c_str());
    AddRequest(strSn, ResCb);
    MkMapString ExternHeader;
    ExternHeader["Event"] = Req.m_Event;
    ExternHeader["Expires"] = std::to_string(Req.m_Expires);
    return SendSipRequest(Req.m_RouterId, Req.m_DstId, Router.SipRealm, MkSipMethodSubscribe, Router.RemoteHost, Router.RemotePort, Router.bTcp, nullptr, ExternHeader, MkSipContentXml, strXml);
}

Uint32 CMkGb28181::NotifyRequest(const CMkGbNotifyRequest& Req, const MkGbResponseCallback& ResCb)
{
    MkVectorString::iterator it = m_SupportQueryCmd.begin();
    for (; it != m_SupportQueryCmd.end(); it++) {
        if (*it == Req.m_CmdType) {
            break;
        }
    }
    if (it == m_SupportQueryCmd.end()) {
        MkErrorLog("input invalid query cmd type:%s\n", Req.m_CmdType.c_str());
        return InvalidParams;
    }
    tinyxml2::XMLDocument doc;
    MkString strSn = std::to_string(m_Sn++);
    MkString strXml;
    doc.InsertFirstChild(doc.NewDeclaration());

    tinyxml2::XMLElement *root = doc.NewElement(Req.m_MessageType.c_str());
    doc.InsertEndChild(root);

    tinyxml2::XMLElement *ItemNode = doc.NewElement("CmdType");
    ItemNode->InsertFirstChild(doc.NewText(Req.m_CmdType.c_str()));
    root->InsertEndChild(ItemNode);

    ItemNode = doc.NewElement("SN");
    ItemNode->InsertFirstChild(doc.NewText(strSn.c_str()));
    root->InsertEndChild(ItemNode);
    if (!Req.m_DeviceId.empty()) {
        ItemNode = doc.NewElement("DeviceID");
        ItemNode->InsertFirstChild(doc.NewText(Req.m_DeviceId.c_str()));
        root->InsertEndChild(ItemNode);
    }
    GbMessageToXml(Req.m_Message, doc, root);

    tinyxml2::XMLPrinter printer;
    doc.Print(&printer);
    strXml = printer.CStr();

    AddRequest(strSn, ResCb);
    MkMapString ExternMap;
    ExternMap["expires"] = std::to_string(Req.m_Expires);
    ExternMap["retry-after"] = "0";
    return SubscribeNotify(Req.m_SubscribeId, Req.m_Event, Req.m_State, ExternMap, MkSipContentXml, strXml, nullptr);
}

Uint32 CMkGb28181::RegisterRequest(const CMkGbDeviceAuthorRequest& Req, const MkGbResponseCallback& Cb)
{
    MkMapString ExternHeader;
    ExternHeader["X-GB-Ver"] = "3.0";
    ExternHeader["Expires"] = std::to_string(Req.m_Expires);
    Uint32 ErrorCode = NoneError;

    SipMsgCompleteCallback SipMsgCb = [this, Cb](const CMkSipMessage& SipMsg) {
        AddRequest(SipMsg.GetTransactionId(), Cb);
    };
    if (Req.m_RegisterId.empty()) {
        MkGbRouter Router;
        ErrorCode = GetRouter(Req.m_RouterId, Router);
        MkCheckErrorLog(ErrorCode, "dst id:%s not found\n", Req.m_RouterId.c_str());

        ErrorCode = SendSipRequest(Req.m_RouterId, Req.m_DstId, Router.SipRealm, MkSipMethodRegister, Router.RemoteHost, Router.RemotePort, Router.bTcp, SipMsgCb, ExternHeader);
    } else {
        MkString strAuthorization;
        if (!Req.m_Algorithm.empty()) {
            strAuthorization = "Digest username=\"" + Req.m_UserName + "\", realm=\"" + Req.m_Realm + "\", nonce=\"" + Req.m_Nonce + "\", uri=\"" + Req.m_Uri + "\", response=\"" + Req.m_Response + "\", algorithm=" + Req.m_Algorithm;
            ExternHeader["Authorization"] = strAuthorization;
        }
        ErrorCode = Register(Req.m_RegisterId, ExternHeader, SipMsgCb);
    }
    return ErrorCode;
}

Uint32 CMkGb28181::InviteRequest(const MkString &RouterId, const MkString& ChannelId, const MkString& Subject, const MkString &OffserSdp, const MkGbResponseCallback &Cb)
{
    Uint32 ErrorCode = NoneError;
    MkMapString MapHeader;
    MapHeader["Subject"] = Subject;
    MkSipContentType ContentType = MkSipContentNone;
    if (!OffserSdp.empty()) {
        ContentType = MkSipContentSdp;
    }
    MkGbRouter Router;
    ErrorCode = GetRouter(RouterId, Router);
    MkCheckErrorLog(ErrorCode, "dst id:%s not found\n", RouterId.c_str());

    return SendSipRequest(RouterId, ChannelId, Router.SipRealm, MkSipMethodInvite, Router.RemoteHost, Router.RemotePort, Router.bTcp, [this, Cb](const CMkSipMessage& SipMsg) {
        AddRequest(SipMsg.GetTransactionId(), Cb);
    }, MapHeader, ContentType, OffserSdp);
}

Uint32 CMkGb28181::ByeRequest(const MkString &PlaySession, const MkGbResponseCallback &Cb)
{
    MkDebugLog("send bye\n");
    return StopCall(PlaySession, [this, Cb](const CMkSipMessage& SipMsg) {
        AddRequest(SipMsg.GetTransactionId(), Cb);
    });
}

Uint32 CMkGb28181::InviteInfoRequest(const MkString& SessionId, const MkGbPlayControlType& ControlType, float fSleep, const Uint32& DragSecond, const MkGbResponseCallback &Cb)
{
    CMkGbRtsp  GbRtsp;
    GbRtsp.SetScale(std::to_string(fSleep));
    switch (ControlType) {
    case MkGbPlayControlPause:
        GbRtsp.SetMethod("PAUSE");
        GbRtsp.SetRange(std::to_string(DragSecond));
        break;
    case MkGbPlayControlReStore:
        GbRtsp.SetMethod("PLAY");
        GbRtsp.SetRange("now");
        break;
    case MkGbPlayControlSeek:
        GbRtsp.SetMethod("PLAY");
        GbRtsp.SetRange(std::to_string(DragSecond));
        break;
    case MkGbPlayControlSetSpeed:
        GbRtsp.SetMethod("PLAY");
        break;
    default:
        break;
    }

    MkString strRtsp;
    Uint32 ErrorCode = GbRtsp.ToString(strRtsp);
    MkCheckErrorLog(ErrorCode, "packet gb play control failed\n");
    return CallInfo(SessionId, MkSipContentRtsp, strRtsp, [this, Cb](const CMkSipMessage& SipMsg) {
        AddRequest(SipMsg.GetTransactionId(), Cb);
    });
}


Uint32 CMkGb28181::DoCheck()
{
    RequestCheck();
    return NoneError;
}

Uint32 CMkGb28181::AddRequest(const MkString& strKey, const MkGbResponseCallback& Cb)
{
    MkGbRequestParam Item;
    Item.Cb = Cb;
    Item.RequestTime = NowMkTime;
    m_RequestLock.Lock();
    m_MapRequest[strKey] = Item;
    m_RequestLock.Unlock();
    return NoneError;
}

Uint32 CMkGb28181::GbResponseCallback(Uint32 ErrorCode, const MkString& strKey, const CMkGbResponse* pRes)
{
    MkGbResponseCallback Cb;
    m_RequestLock.Lock();
    MapRequest::iterator it = m_MapRequest.find(strKey);
    if (it != m_MapRequest.end()) {
        Cb = it->second.Cb;
        const CMkGbMessageResponse* pMessageRes = dynamic_cast<const CMkGbMessageResponse*>(pRes);
        if (pMessageRes) {
            it->second.CurResponsed += pMessageRes->m_Message.VecChildren.size();
            MkDebugLog("cur size:%d  total size:%d\n", it->second.CurResponsed, pMessageRes->m_SumNum);
            if (pMessageRes->m_SumNum <= it->second.CurResponsed) {
                m_MapRequest.erase(it);
            }
        } else {
            m_MapRequest.erase(it);
        }
    }
    m_RequestLock.Unlock();
    if (Cb) {
        Cb(ErrorCode, pRes);
    }
    return NoneError;
}

Uint32 CMkGb28181::OnSipRequest(const MkSipRequestEvent& RequestEvent, const CMkSipMessage& SipRequest, const EventRequestCallback& Cb)
{
    Uint32 ErrorCode = NoneError;
    MkString FromId = SipRequest.GetFrom().GetUri().GetUserName();
    MkString RouterId = SipRequest.GetTo().GetUri().GetUserName();
    MkString DstId = SipRequest.GetUri().GetUserName();
    if (m_bCheckDstId) {
        // check router is this sip id
        if (MkSipMethodRegister == SipRequest.GetMethod()) {
            RouterId = DstId;
        }
        if (RouterId != GetSipId()) {
            return InvalidParams;
        }
    }
    switch (RequestEvent) {
    case MkSipRequestRegister:
        ErrorCode = RegisterRequestParse(FromId, DstId, SipRequest, Cb);
        break;
    case MkSipRequestMessage:
        ErrorCode = MessageRequestParse(FromId, DstId, SipRequest.GetBody(), Cb);
        break;
    case MkSipRequestInvite:
        ErrorCode = InviteRequestParse(FromId, DstId, SipRequest, Cb);
        break;
    case MkSipRequestInviteMessage:
        ErrorCode = InviteMessageRequestParse(FromId, DstId, SipRequest, Cb);
        break;
    case MkSipRequestInviteInfo:
        ErrorCode = InviteInfoRequestParse(FromId, DstId, SipRequest, Cb);
        break;
    case MkSipRequestSubscribe:
        ErrorCode = SubscribeRequestParse(FromId, DstId, SipRequest, Cb);
        break;
    case MkSipRequestSubscribeNotify:
        ErrorCode = SubscribeNotifyRequestParse(FromId, DstId, SipRequest, Cb);
        break;
    case MkSipRequestBye:
        ErrorCode = ByeRequestParse(FromId, DstId, SipRequest, Cb);
        break;
    case MkSipRequestAck:
        ErrorCode = AckRequestParse(FromId, DstId, SipRequest, Cb);
        break;
    default:
        break;
    }
    return ErrorCode;
}

Uint32 CMkGb28181::OnSipResponse(const MkSipResponseEvent& ResponseEvent, const MkString& TransActionId, const CMkSipMessage& SipRequest, const CMkSipMessage& SipResponse, const EventResponseCallback& Cb)
{
    Uint32 ErrorCode = NoneError;
    switch (ResponseEvent) {
    case MkSipResponseRegister:
        ErrorCode = ResponseRegisterParse(SipRequest, SipResponse);
        break;
    case MkSipResponseMessage:
        ErrorCode = ResponseMessageParse(SipRequest, SipResponse);
        break;
    case MkSipResponseInvite:
        ErrorCode = ResponseInviteParse(SipRequest, SipResponse, Cb);
        break;
    case MkSipResponseSubscribe:
        ErrorCode = ResponseSubscribeParse(SipRequest, SipResponse);
        break;
    case MkSipResponseSubscribeNotify:
    case MkSipResponseBye:
    case MkSipResponseInviteInfo:
    case MkSipResponseInviteMessage:
        ErrorCode = GbResponseCallback(MkSipStatusOK == SipResponse.GetStatusCode() ? NoneError : SystemError, TransActionId, nullptr);
        break;
    default:
        break;
    }
    return ErrorCode;
}

Uint32 CMkGb28181::RegisterRequestParse(const MkString& FromId, const MkString& DstId, const CMkSipMessage& SipRequest, const EventRequestCallback& EventCallback)
{
    MkMapString ExternHeaders;
    ExternHeaders["X-GB-Ver"] = "3.0";
    if (SipRequest.GetVecAuthorization().empty()) {
        MkString Nonce;
        CMkUtil::CreateRandomString(16, Nonce);
        MkString WWW_Authenticate = "Digest realm=\"" + GetRealm() + "\",algorithm=MD5,nonce=\"" + Nonce + "\",stale=false";
        ExternHeaders["WWW-Authenticate"] = WWW_Authenticate;
        EventCallback(MkSipStatusUnauthorized, ExternHeaders, MkSipContentNone, "");
        return NoneError;
    }
    Uint32 ErrorCode = NoneError;
    MkString DeviceRealm;
    if (0 == SipRequest.GetFrom().GetUri().GetPort()) {
        DeviceRealm = SipRequest.GetFrom().GetUri().GetHost();
    }
    CMkSipAuthorization SipAuthorization = *(SipRequest.GetVecAuthorization()).begin();
    MkString UserName;
    MkString Realm;
    MkString Nonce;
    MkString Uri;
    MkString Response;
    MkString Algorithm;
    ErrorCode = SipAuthorization.GetParam("username", UserName);
    MkCheckErrorLog(ErrorCode, "get value failed\n");
    ErrorCode = SipAuthorization.GetParam("realm", Realm);
    MkCheckErrorLog(ErrorCode, "get value failed\n");
    ErrorCode = SipAuthorization.GetParam("nonce", Nonce);
    MkCheckErrorLog(ErrorCode, "get value failed\n");
    ErrorCode = SipAuthorization.GetParam("uri", Uri);
    MkCheckErrorLog(ErrorCode, "get value failed\n");
    ErrorCode = SipAuthorization.GetParam("response", Response);
    MkCheckErrorLog(ErrorCode, "get value failed\n");
    ErrorCode = SipAuthorization.GetParam("algorithm", Algorithm);
    MkCheckErrorLog(ErrorCode, "get value failed\n");

    MkString StrExpries;
    Uint32 uExpires = 0;
    ErrorCode = SipRequest.GetHeaderValue("Expires", StrExpries);
    if (NoneError == ErrorCode) {
        uExpires = std::stoi(StrExpries);
        if (0 != uExpires) {
            if (uExpires > m_RegisterExpries) {
                uExpires = m_RegisterExpries;
            }
        }
    } else { //not has expires header set defalut
        uExpires = m_RegisterExpries;
    }

    CMkGbDeviceAuthorRequest Req;
    Req.m_DstId = DstId;
    Req.m_FromId = FromId;
    Req.m_DeviceHost = SipRequest.GetRemoteHost();
    Req.m_DevicePort = SipRequest.GetRemotePort();
    Req.m_AuthorType = SipAuthorization.GetAuthType();
    Req.m_UserName = UserName;
    Req.m_Nonce = Nonce;
    Req.m_Uri = Uri;
    Req.m_Response = Response;
    Req.m_Algorithm = Algorithm;
    Req.m_Expires = uExpires;
    Req.m_RegisterId = SipRequest.GetDialogId();
    return  m_ReqCb(&Req, [this, FromId, DeviceRealm, SipRequest, uExpires, EventCallback](Uint32 ErrorCode, const CMkGbResponse* pGbRes) {
        MkMapString ExternHeaders;
        const CMkGbDeviceAuthorResponse* pAuthorRes = dynamic_cast<const CMkGbDeviceAuthorResponse*>(pGbRes);
        ExternHeaders["X-GB-Ver"] = "3.0";
        if (NoneError != ErrorCode || !pAuthorRes) {
            EventCallback(MkSipStatusNotFound, ExternHeaders, MkSipContentNone, "");
            return InvalidParams;
        }

        if (!pAuthorRes->m_bRedirect) {
            MkString strNowTime;
            NowMkTime.GetString(strNowTime, "T", "", TRUE);
            ExternHeaders.insert(std::pair<MkString, MkString>("Date", strNowTime));
            ExternHeaders.insert(std::pair<MkString, MkString>("Expires", std::to_string(uExpires)));
            EventCallback(MkSipStatusOK, ExternHeaders, MkSipContentNone, "");
            if (0 == uExpires) {
                DeleteRouter(FromId);
            } else {
                AddRouter(FromId, DeviceRealm, SipRequest.GetRemoteHost(), SipRequest.GetRemotePort(), SipRequest.IsTcp());
            }
        } else {
            ExternHeaders["Contact"] = "<sip:" + pAuthorRes->m_RedirectId + "@" + pAuthorRes->m_RedirectHost + ":" + std::to_string(pAuthorRes->m_RedirectPort) + ">";
            EventCallback(MkSipStatusMovedTemporarily, ExternHeaders, MkSipContentNone, "");
        }
        return NoneError;
    });
}

Uint32 CMkGb28181::MessageRequestParse(const MkString& FromId, const MkString& DstId, const MkString& RequestBody, const EventRequestCallback& EventCallback)
{
    Uint32 ErrorCode = NoneError;
    MkGbRouter Router;
    ErrorCode = GetRouter(FromId, Router);
    MkCheckErrorLog(ErrorCode, "get router info failed\n");

    tinyxml2::XMLDocument doc;
    ErrorCode = doc.Parse(RequestBody.c_str());
    if (tinyxml2::XML_SUCCESS != ErrorCode) {
        return XmlErrorCodeBegin + ErrorCode;
    }
    tinyxml2::XMLElement *pElement = doc.FirstChildElement();
    if (!pElement) {
        return InvalidParams;
    }
    MkString MessageType = CMkUtil::SafeMkString(pElement->Name());
    if ("Response" == MessageType) {
        ErrorCode = MessageResponseParse(pElement, EventCallback);
    } else {
        ErrorCode = MessageGbRequestParse(FromId, DstId, MessageType, pElement, EventCallback);
    }
    return ErrorCode;
}

Uint32 CMkGb28181::InviteRequestParse(const MkString& FromId, const MkString& DstId, const CMkSipMessage& SipRequest, const EventRequestCallback& EventCallback)
{
    MkString Subject;
    Uint32 ErrorCode = SipRequest.GetHeaderValue("Subject", Subject);
    MkCheckErrorLog(ErrorCode, "get subject header failed\n");
    MkVectorString VesStr;
    ErrorCode = CMkUtil::StringSplit(Subject, ",", VesStr);
    CMkGbInviteReqeust Req;
    Req.m_DstId = DstId;
    Req.m_FromId = FromId;
    Req.m_OfferSdp = SipRequest.GetBody();
    Req.m_SessionId = SipRequest.GetDialogId();
    Req.m_SubjectSource = VesStr[0];
    return  m_ReqCb(&Req, [this, EventCallback](Uint32 ErrorCode, const CMkGbResponse* pGbRes) {
        const CMkGbInviteResponse* pInviteRes = dynamic_cast<const CMkGbInviteResponse*>(pGbRes);
        if (NoneError != ErrorCode || !pGbRes) {
            EventCallback(NoneError == ErrorCode ? MkSipStatusOK : MkSipStatusBadRequest, MkMapString(), MkSipContentNone, "");
            return;
        }
        EventCallback(MkSipStatusOK, MkMapString(), MkSipContentSdp, pInviteRes->m_AnwserSdp);
    });
}

Uint32 CMkGb28181::SubscribeRequestParse(const MkString& FromId, const MkString& DstId, const CMkSipMessage& SipRequest, const EventRequestCallback& EventCallback)
{
    Uint32 ErrorCode = NoneError;
    MkGbRouter Router;
    ErrorCode = GetRouter(FromId, Router);
    MkCheckErrorLog(ErrorCode, "get routerid:%s failed\n", FromId.c_str());
    tinyxml2::XMLDocument doc;
    ErrorCode = doc.Parse(SipRequest.GetBody().c_str());
    if (tinyxml2::XML_SUCCESS != ErrorCode) {
        return XmlErrorCodeBegin + ErrorCode;
    }
    tinyxml2::XMLElement *pElement = doc.FirstChildElement();
    if (!pElement) {
        return InvalidParams;
    }
    MkString MessageType = CMkUtil::SafeMkString(pElement->Name());
    if ("Query" != MessageType) {
        return InvalidParams;
    }
    const tinyxml2::XMLElement *CmdTypeElement = pElement->FirstChildElement("CmdType");
    const tinyxml2::XMLElement *SnElement = pElement->FirstChildElement("SN");
    const tinyxml2::XMLElement *DeviceIdElement = pElement->FirstChildElement("DeviceID");
    MkMapString::const_iterator itExpires = SipRequest.GetOtherHeaders().find("Expires");
    MkMapString::const_iterator itEvent = SipRequest.GetOtherHeaders().find("Event");
    if (!CmdTypeElement
        || !SnElement
        || !DeviceIdElement
        || itExpires == SipRequest.GetOtherHeaders().end()
        || itEvent == SipRequest.GetOtherHeaders().end()) {
        MkErrorLog("not has item cmdtype\n");
        return InvalidParams;
    }
    CMkGbSubscribeRequest GbReq;
    GbReq.m_SubscribeId = SipRequest.GetDialogId();
    MkString StrSn = CMkUtil::SafeMkString(SnElement->GetText());
    MkString CmdType = CMkUtil::SafeMkString(CmdTypeElement->GetText());
    MkString DeviceId = CMkUtil::SafeMkString(DeviceIdElement->GetText());
    GbReq.m_DstId = DstId;
    GbReq.m_FromId = FromId;
    GbReq.m_DeviceId = DeviceId;
    GbReq.m_MessageType = MessageType;
    GbReq.m_CmdType = CmdType;
    GbReq.m_Expires = CMkUtil::SafeAtoi(itExpires->second.c_str());
    GbReq.m_Event = itEvent->second;
    const tinyxml2::XMLElement *pContentElement = DeviceIdElement->NextSiblingElement();
    XmlToGbMessage(pContentElement, GbReq.m_Message);
    return m_ReqCb(&GbReq, [this, DeviceId, StrSn, itEvent, itExpires, CmdType, EventCallback](Uint32 ErrorCode, const CMkGbResponse* pGbRes) {
        tinyxml2::XMLDocument doc;
        doc.InsertFirstChild(doc.NewDeclaration());
        tinyxml2::XMLElement *root = doc.NewElement("Response");
        doc.InsertEndChild(root);

        tinyxml2::XMLElement *ItemNode = doc.NewElement("CmdType");
        ItemNode->InsertFirstChild(doc.NewText(CmdType.c_str()));
        root->InsertEndChild(ItemNode);

        ItemNode = doc.NewElement("SN");
        ItemNode->InsertFirstChild(doc.NewText(StrSn.c_str()));
        root->InsertEndChild(ItemNode);

        ItemNode = doc.NewElement("DeviceID");
        ItemNode->InsertFirstChild(doc.NewText(DeviceId.c_str()));
        root->InsertEndChild(ItemNode);

        ItemNode = doc.NewElement("Result");
        ItemNode->InsertFirstChild(doc.NewText(NoneError == ErrorCode ? "OK" : "ERROR"));
        root->InsertEndChild(ItemNode);

        MkMapString MapHeader;
        MapHeader["Expires"] = itExpires->second;
        MapHeader["Event"] = itEvent->second;
        tinyxml2::XMLPrinter printer;
        doc.Print(&printer);
        EventCallback(MkSipStatusOK, MapHeader, MkSipContentXml, printer.CStr());
        return NoneError;
    });
}

Uint32 CMkGb28181::InviteMessageRequestParse(const MkString& FromId, const MkString& DstId, const CMkSipMessage& SipRequest, const EventRequestCallback& EventCallback)
{
    //RemotePlayEnd(SipRequest.GetDialogId());
    EventCallback(MkSipStatusOK, MkMapString(), MkSipContentNone, "");
    return NoneError;
}

Uint32 CMkGb28181::SubscribeNotifyRequestParse(const MkString& FromId, const MkString& DstId, const CMkSipMessage& SipRequest, const EventRequestCallback& EventCallback)
{
    Uint32 ErrorCode = NoneError;
    MkGbRouter Router;
    ErrorCode = GetRouter(FromId, Router);
    MkCheckErrorLog(ErrorCode, "get routerid:%s failed\n", FromId.c_str());
    tinyxml2::XMLDocument doc;
    ErrorCode = doc.Parse(SipRequest.GetBody().c_str());
    if (tinyxml2::XML_SUCCESS != ErrorCode) {
        return XmlErrorCodeBegin + ErrorCode;
    }
    tinyxml2::XMLElement *pElement = doc.FirstChildElement();
    if (!pElement) {
        return InvalidParams;
    }
    MkString MessageType = CMkUtil::SafeMkString(pElement->Name());
    if ("Notify" != MessageType) {
        return InvalidParams;
    }
    const tinyxml2::XMLElement *CmdTypeElement = pElement->FirstChildElement("CmdType");
    const tinyxml2::XMLElement *SnElement = pElement->FirstChildElement("SN");
    const tinyxml2::XMLElement *DeviceIdElement = pElement->FirstChildElement("DeviceID");
    MkMapString::const_iterator itState = SipRequest.GetOtherHeaders().find("Subscription-State");
    MkMapString::const_iterator itEvent = SipRequest.GetOtherHeaders().find("Event");
    if (!CmdTypeElement
        || !SnElement
        || !DeviceIdElement
        || itState == SipRequest.GetOtherHeaders().end()
        || itEvent == SipRequest.GetOtherHeaders().end()) {
        MkErrorLog("not has item cmdtype\n");
        return InvalidParams;
    }
    CMkGbNotifyRequest GbReq;
    GbReq.m_SubscribeId = SipRequest.GetDialogId();
    MkString StrSn = CMkUtil::SafeMkString(SnElement->GetText());
    MkString CmdType = CMkUtil::SafeMkString(CmdTypeElement->GetText());
    MkString DeviceId = CMkUtil::SafeMkString(DeviceIdElement->GetText());
    GbReq.m_DeviceId = DeviceId;
    GbReq.m_DstId = DstId;
    GbReq.m_FromId = FromId;
    GbReq.m_MessageType = MessageType;
    GbReq.m_CmdType = CmdType;
    GbReq.m_Expires = 0;
    GbReq.m_Event = itEvent->second;
    MkVectorString VecString;
    CMkUtil::StringSplit(itState->second, ";", VecString);
    GbReq.m_State = VecString[0];
    for (size_t i = 1; i < VecString.size(); i++) {
        size_t nPos = VecString[i].find("expires");
        if (MkString::npos != nPos) {
            GbReq.m_Expires = std::stoi(VecString[i].substr(strlen("expires") + 1));
            break;
        }
    }
    const tinyxml2::XMLElement *pContentElement = DeviceIdElement->NextSiblingElement();
    XmlToGbMessage(pContentElement, GbReq.m_Message);
    return m_ReqCb(&GbReq, [this, DeviceId, StrSn, CmdType, EventCallback](Uint32 ErrorCode, const CMkGbResponse* pGbRes) {
        tinyxml2::XMLDocument doc;
        doc.InsertFirstChild(doc.NewDeclaration());
        tinyxml2::XMLElement *root = doc.NewElement("Response");
        doc.InsertEndChild(root);

        tinyxml2::XMLElement *ItemNode = doc.NewElement("CmdType");
        ItemNode->InsertFirstChild(doc.NewText(CmdType.c_str()));
        root->InsertEndChild(ItemNode);

        ItemNode = doc.NewElement("SN");
        ItemNode->InsertFirstChild(doc.NewText(StrSn.c_str()));
        root->InsertEndChild(ItemNode);

        ItemNode = doc.NewElement("DeviceID");
        ItemNode->InsertFirstChild(doc.NewText(DeviceId.c_str()));
        root->InsertEndChild(ItemNode);

        ItemNode = doc.NewElement("Result");
        ItemNode->InsertFirstChild(doc.NewText(NoneError == ErrorCode ? "OK" : "ERROR"));
        root->InsertEndChild(ItemNode);

        tinyxml2::XMLPrinter printer;
        doc.Print(&printer);
        EventCallback(MkSipStatusOK, MkMapString(), MkSipContentXml, printer.CStr());
        return NoneError;
    });
}

Uint32 CMkGb28181::ByeRequestParse(const MkString& FromId, const MkString& DstId, const CMkSipMessage& SipRequest, const EventRequestCallback& EventCallback)
{
    MkDebugLog("recv bye\n");
    CMkGbByeReqeust Req;
    Req.m_DstId = DstId;
    Req.m_FromId = FromId;
    Req.m_SessionId = SipRequest.GetDialogId();
    return m_ReqCb(&Req, [this, EventCallback](Uint32 ErrorCode, const CMkGbResponse* pRes) {
        EventCallback(NoneError == ErrorCode ? MkSipStatusOK : MkSipStatusCallDoesNotExist, MkMapString(), MkSipContentNone, "");
    });
}

Uint32 CMkGb28181::AckRequestParse(const MkString& FromId, const MkString& DstId, const CMkSipMessage& SipRequest, const EventRequestCallback& EventCallback)
{
    CMkGbAckReqeust Req;
    Req.m_DstId = DstId;
    Req.m_FromId = FromId;
    Req.m_SessionId = SipRequest.GetDialogId();
    Req.m_RemoteSdp = SipRequest.GetBody();
    Uint32 ErrorCode = m_ReqCb(&Req, nullptr);
    if (NoneError != ErrorCode) {
        ByeRequest(Req.m_SessionId, nullptr);
    }
    return NoneError;
}

Uint32 CMkGb28181::InviteInfoRequestParse(const MkString& FromId, const MkString& DstId, const CMkSipMessage& SipRequest, const EventRequestCallback& EventCallback)
{
    CMkGbInviteInfoRequest Req;
    CMkGbRtsp Rtsp;
    Uint32 ErrorCode = Rtsp.AddContent(SipRequest.GetBody());
    MkCheckErrorLog(ErrorCode, "content:%s parse failed\n", SipRequest.GetBody().c_str());
    if ("PAUSE" == Rtsp.GetMethod()) {
        Req.m_ControlType = MkGbPlayControlPause;
    } else if ("PLAY" == Rtsp.GetMethod()) {
        if (Rtsp.GetScale().empty() || 1.0 == std::stof(Rtsp.GetScale())) {
            if ("now" == Rtsp.GetRange()) {
                Req.m_ControlType = MkGbPlayControlReStore;
            } else {
                Req.m_ControlType = MkGbPlayControlSeek;
                Req.m_DragSecond = std::atoi(Rtsp.GetRange().c_str());
            }
        } else {
            Req.m_ControlType = MkGbPlayControlSetSpeed;
            Req.m_fSleep = std::stof(Rtsp.GetScale());
        }
    }
    return m_ReqCb(&Req, [this, EventCallback](Uint32 ErrorCode, const CMkGbResponse* pRes) {
        const CMkGbInviteInfoResponse* pInviteInfoRes = dynamic_cast<const CMkGbInviteInfoResponse*>(pRes);
        if (!pInviteInfoRes) {
            EventCallback(MkSipStatusServerInternalError, MkMapString(), MkSipContentNone, "");
            return;
        }
        CMkGbRtsp GbRtsp;
        GbRtsp.SetScale(std::to_string(pInviteInfoRes->m_fSleep));
        switch (pInviteInfoRes->m_ControlType) {
        case MkGbPlayControlPause:
            GbRtsp.SetMethod("PAUSE");
            break;
        case MkGbPlayControlReStore:
            GbRtsp.SetMethod("PLAY");
            GbRtsp.SetRange("now");
            break;
        case MkGbPlayControlSeek:
            GbRtsp.SetMethod("PLAY");
            GbRtsp.SetRange(std::to_string(pInviteInfoRes->m_DragSecond));
            break;
        case MkGbPlayControlSetSpeed:
            GbRtsp.SetMethod("PLAY");
            break;
        default:
            break;
        }
        MkString StringRtsp;
        GbRtsp.ToString(StringRtsp);
        EventCallback(MkSipStatusOK, MkMapString(), MkSipContentRtsp, StringRtsp);
    });
}

Uint32 CMkGb28181::ResponseInviteParse(const CMkSipMessage& SipRequest, const CMkSipMessage& SipResponse, const EventResponseCallback& Cb)
{
    MkString AnswerSdp = SipResponse.GetBody();
    CMkGbInviteResponse Res;
    Res.m_AnwserSdp = AnswerSdp;
    Res.m_EventResCb = Cb;
    Res.m_SessionId = SipRequest.GetDialogId();
    GbResponseCallback(MkSipStatusOK != SipResponse.GetStatusCode() ? SipResponseErrorBegin + SipResponse.GetStatusCode() : NoneError, SipResponse.GetTransactionId(), &Res);
    return NoneError;
}

Uint32 CMkGb28181::ResponseSubscribeParse(const CMkSipMessage& SipRequest, const CMkSipMessage& SipResponse)
{
    const tinyxml2::XMLElement *SnElement = nullptr;
    const tinyxml2::XMLElement *CmdElement = nullptr;
    const tinyxml2::XMLElement *DeviceIdElement = nullptr;
    tinyxml2::XMLDocument doc;
    tinyxml2::XMLError ErrorCode = tinyxml2::XML_SUCCESS;

    if (MkSipStatusOK == SipResponse.GetStatusCode()) {
        doc.Parse(SipResponse.GetBody().c_str());
        if (tinyxml2::XML_SUCCESS != ErrorCode) {
            return XmlErrorCodeBegin + ErrorCode;
        }
        tinyxml2::XMLElement *ResponseElement = doc.FirstChildElement("Response");
        if (!ResponseElement) {
            return UnknownError;
        }
        SnElement = ResponseElement->FirstChildElement("SN");
        CmdElement = ResponseElement->FirstChildElement("Cmd");
        DeviceIdElement = ResponseElement->FirstChildElement("DeviceID");
    } else {
        doc.Parse(SipRequest.GetBody().c_str());
        if (tinyxml2::XML_SUCCESS != ErrorCode) {
            return XmlErrorCodeBegin + ErrorCode;
        }
        tinyxml2::XMLElement *RequestElement = doc.FirstChildElement("Query");
        if (!RequestElement) {
            return UnknownError;
        }
        SnElement = RequestElement->FirstChildElement("SN");
        CmdElement = RequestElement->FirstChildElement("Cmd");
        DeviceIdElement = RequestElement->FirstChildElement("DeviceID");
    }

    if (!SnElement) {
        return UnknownError;
    }
    CMkGbSubscribeResponse Res;
    //Res.m_RouterId = SipRequest.GetTo().GetUri().GetUserName();
    Res.m_SubscribeId = SipRequest.GetDialogId();
    //Res.m_DstId = Res.m_RouterId;
    const tinyxml2::XMLElement *pElement = SnElement->NextSiblingElement();
    if (DeviceIdElement) {
        pElement = DeviceIdElement->NextSiblingElement();
        //Res.m_DstId = CMkUtil::SafeMkString(DeviceIdElement->GetText());
    }
    if (MkSipStatusOK == SipResponse.GetStatusCode()) {
        XmlToGbMessage(pElement, Res.m_Message);
        GbResponseCallback(NoneError, CMkUtil::SafeMkString(SnElement->GetText()), &Res);
    } else {
        GbResponseCallback(SipResponseErrorBegin + SipResponse.GetStatusCode(), CMkUtil::SafeMkString(SnElement->GetText()), nullptr);
    }

    return NoneError;
}

Uint32 CMkGb28181::ResponseRegisterParse(const CMkSipMessage& SipRequest, const CMkSipMessage& SipResponse)
{
    Uint32 ErrorCode = NoneError;
    CMkGbDeviceAuthorResponse Res;
    Res.m_RegisterId = SipResponse.GetDialogId();
    SipRequest.GetUri().ToString(Res.m_Uri);
    if (MkSipStatusUnauthorized == SipResponse.GetStatusCode()) {
        MkVector<CMkSipWwwAuthenticate> VecAuth = SipResponse.GetVecWwwAuthenticate();
        if (!VecAuth.empty()) {
            Res.m_AuthType = VecAuth.begin()->GetAuthType();
            VecAuth.begin()->GetParam("realm", Res.m_Realm);
            VecAuth.begin()->GetParam("algorithm", Res.m_Algorithm);
            VecAuth.begin()->GetParam("nonce", Res.m_Nonce);
        }
    }
    if (MkSipStatusOK != SipResponse.GetStatusCode()) {
        ErrorCode = SipResponseErrorBegin + SipResponse.GetStatusCode();
    } else {
        MkString strExpires;
        SipResponse.GetHeaderValue("Expires", strExpires);
        Res.m_Expires = std::stoi(strExpires);
    }
    return GbResponseCallback(ErrorCode, SipRequest.GetTransactionId(), &Res);
}

Uint32 CMkGb28181::ResponseMessageParse(const CMkSipMessage& SipRequest, const CMkSipMessage& SipResponse)
{
    tinyxml2::XMLDocument doc;
    Uint32 ErrorCode = tinyxml2::XML_SUCCESS;
    doc.Parse(SipRequest.GetBody().c_str());
    if (tinyxml2::XML_SUCCESS != ErrorCode) {
        return XmlErrorCodeBegin + ErrorCode;
    }
    const tinyxml2::XMLElement *pRootElement = doc.FirstChildElement();
    const tinyxml2::XMLElement *pSnElement = nullptr;
    if (pRootElement) {
        pSnElement = pRootElement->FirstChildElement("SN");
    }

    if (!pRootElement || !pSnElement) {
        return InvalidParams;
    }
    if (MkSipStatusOK != SipResponse.GetStatusCode()) {
        return GbResponseCallback(SipResponse.GetStatusCode() + SipResponseErrorBegin, CMkUtil::SafeMkString(pSnElement->GetText()), nullptr);
    }
    if ("Notify" == CMkUtil::SafeMkString(pRootElement->Name())) {
        return GbResponseCallback(NoneError, CMkUtil::SafeMkString(pSnElement->GetText()), nullptr);
    }
    tinyxml2::XMLElement *RequestElement = doc.FirstChildElement("Query");
    if (nullptr != RequestElement) {
        ErrorCode = ResponseMessageQueryParse(RequestElement, SipRequest, SipResponse);
    }

    RequestElement = doc.FirstChildElement("Control");
    if (nullptr != RequestElement) {
        ErrorCode = ResponseMessageControlParse(RequestElement, SipRequest, SipResponse);
    }
    return ErrorCode;
}

Uint32 CMkGb28181::ResponseMessageQueryParse(const tinyxml2::XMLElement* pElement, const CMkSipMessage& SipRequest, const CMkSipMessage& SipResponse)
{
    const tinyxml2::XMLElement *SnElement = pElement->FirstChildElement("SN");
    if (!SnElement) {
        return UnknownError;
    }
    MkString strSn = SnElement->GetText();
    //if (MkSipStatusOK != SipResponse.GetStatusCode()) {
    //    return ResponseCallback(SystemError, strSn, nullptr);
    //}
    return NoneError;
}

Uint32 CMkGb28181::ResponseMessageControlParse(const tinyxml2::XMLElement* pElement, const CMkSipMessage& SipRequest, const CMkSipMessage& SipResponse)
{
    const tinyxml2::XMLElement *SnElement = pElement->FirstChildElement("SN");
    if (!SnElement) {
        return UnknownError;
    }
    MkString strSn = SnElement->GetText();
    if (MkSipStatusOK != SipResponse.GetStatusCode()) {
        return GbResponseCallback(SystemError, strSn, nullptr);
    } else {
        const tinyxml2::XMLElement *CmdType = pElement->FirstChildElement("CmdType");
        MkString strCmdType = CMkUtil::SafeMkString(CmdType->GetText());
        if ("DeviceControl" == strCmdType) {
            //the flowing control type not has response
            if (pElement->FirstChildElement("PTZCmd")
                || pElement->FirstChildElement("IFrameCmd")
                || pElement->FirstChildElement("TeleBoot")
                || pElement->FirstChildElement("DragZoomIn")
                || pElement->FirstChildElement("DragZoomOut")
                || pElement->FirstChildElement("PTZPreciseCtrl")
                || pElement->FirstChildElement("FormatSDCards")
                || pElement->FirstChildElement("TargetTrack")) {
                return GbResponseCallback(NoneError, strSn, nullptr);
            }
        }
    }
    return NoneError;
}

Uint32 CMkGb28181::MessageGbRequestParse(const MkString& FromId, const MkString& DstId, const MkString& MessageType, const tinyxml2::XMLElement *pElement, const EventRequestCallback& EventCallback)
{
    const tinyxml2::XMLElement *CmdTypeElement = pElement->FirstChildElement("CmdType");
    const tinyxml2::XMLElement *SumNumElement = pElement->FirstChildElement("SumNum");
    const tinyxml2::XMLElement *SnElement = pElement->FirstChildElement("SN");
    const tinyxml2::XMLElement *DeviceIdElement = pElement->FirstChildElement("DeviceID");
    if (!CmdTypeElement
        || !SnElement) {
        MkErrorLog("not has item cmdtype\n");
        return InvalidParams;
    }
    MkString StrSn = CMkUtil::SafeMkString(SnElement->GetText());
    MkString CmdType = CMkUtil::SafeMkString(CmdTypeElement->GetText());
    MkString DeviceId;
    CMkGbMessageRequest GbReq;
    GbReq.m_DstId = DstId;
    GbReq.m_FromId = FromId;
    GbReq.m_MessageType = MessageType;
    GbReq.m_CmdType = CmdType;
    const tinyxml2::XMLElement *pContentElement = SnElement->NextSiblingElement();
    if (DeviceIdElement) {
        GbReq.m_DeviceId = CMkUtil::SafeMkString(DeviceIdElement->GetText());
        pContentElement = DeviceIdElement->NextSiblingElement();
    }
    XmlToGbMessage(pContentElement, GbReq.m_Message);
    return m_ReqCb(&GbReq, [this, FromId, DstId, DeviceId, StrSn, CmdType, EventCallback](Uint32 ErrorCode, const CMkGbResponse* pGbRes) {
        const CMkGbMessageResponse* pMsgRes = dynamic_cast<const CMkGbMessageResponse*>(pGbRes);
        EventCallback(NoneError == ErrorCode ? MkSipStatusOK : MkSipStatusBadRequest, MkMapString(), MkSipContentNone, "");
        if (pMsgRes) {
            if (1 >= pMsgRes->m_SumNum) {
                SendMessageResponse(FromId, DstId, DeviceId, StrSn, CmdType, *pMsgRes);
            } else {
                CMkGbMessageResponse TmpRes = *pMsgRes;
                for (Uint32 i = 0; i < pMsgRes->m_SumNum && i < pMsgRes->m_Message.VecChildren.size(); i++) {
                    TmpRes.m_Message.VecChildren.clear();
                    TmpRes.m_Message.VecChildren.push_back(pMsgRes->m_Message.VecChildren[i]);
                    SendMessageResponse(FromId, DstId, DeviceId, StrSn, CmdType, TmpRes);
                }
            }
        }
        return NoneError;
    });
}

Uint32 CMkGb28181::MessageResponseParse(const tinyxml2::XMLElement *pElement, const EventRequestCallback& EventCallback)
{
    Uint32 ErrorCode = UnSupported;
    const tinyxml2::XMLElement *CmdTypeElement = pElement->FirstChildElement("CmdType");
    const tinyxml2::XMLElement *SumNumElement = pElement->FirstChildElement("SumNum");
    const tinyxml2::XMLElement *SnElement = pElement->FirstChildElement("SN");
    const tinyxml2::XMLElement *DeviceIdElement = pElement->FirstChildElement("DeviceID");
    if (!CmdTypeElement
        || !SnElement) {
        MkErrorLog("not has item cmdtype\n");
        return InvalidParams;
    }
    MkString CmdType = CMkUtil::SafeMkString(CmdTypeElement->GetText());
    CMkGbMessageResponse Res;
    if (SumNumElement) {
        Res.m_SumNum = CMkUtil::SafeAtoi(SumNumElement->GetText());
    }
    const tinyxml2::XMLElement *pNode = SnElement->NextSiblingElement();
    if (DeviceIdElement) {
        //Res.m_DstId = CMkUtil::SafeMkString(DeviceIdElement->GetText());
        pNode = DeviceIdElement->NextSiblingElement();
    }
    XmlToGbMessage(pNode, Res.m_Message);
    EventCallback(MkSipStatusOK, MkMapString(), MkSipContentNone, "");
    return GbResponseCallback(NoneError, CMkUtil::SafeMkString(SnElement->GetText()), &Res);
}

Uint32 CMkGb28181::SendMessageResponse(const MkString& RouterId, const MkString& DstId, const MkString& DeviceId, const MkString& StrSn, const MkString& CmdType, const CMkGbMessageResponse& Res)
{
    tinyxml2::XMLDocument doc;
    Uint32 ErrorCode = NoneError;
    MkString strXml;
    doc.InsertFirstChild(doc.NewDeclaration());
    tinyxml2::XMLElement *root = doc.NewElement("Response");
    doc.InsertEndChild(root);

    tinyxml2::XMLElement *ItemNode = doc.NewElement("CmdType");
    ItemNode->InsertFirstChild(doc.NewText(CmdType.c_str()));
    root->InsertEndChild(ItemNode);

    ItemNode = doc.NewElement("SN");
    ItemNode->InsertFirstChild(doc.NewText(StrSn.c_str()));
    root->InsertEndChild(ItemNode);

    ItemNode = doc.NewElement("DeviceID");
    ItemNode->InsertFirstChild(doc.NewText(DeviceId.c_str()));
    root->InsertEndChild(ItemNode);

    if (Res.m_Message.VecChildren.empty()
        && ("Catalog" == CmdType || "RecordInfo" == CmdType || "PresetQuery" == CmdType || "CruiseTrackListQuery" == CmdType || "CruiseTrackQuery" == CmdType)) {
        ItemNode = doc.NewElement("SumNum");
        ItemNode->InsertFirstChild(doc.NewText("0"));
        root->InsertEndChild(ItemNode);
    } else {
        if (Res.m_SumNum) {
            ItemNode = doc.NewElement("SumNum");
            ItemNode->InsertFirstChild(doc.NewText(std::to_string(Res.m_SumNum).c_str()));
            root->InsertEndChild(ItemNode);
        }
        GbMessageToXml(Res.m_Message, doc, root);
    }
    tinyxml2::XMLPrinter printer;
    doc.Print(&printer);
    strXml = printer.CStr();

    MkGbRouter Router;
    ErrorCode = GetRouter(RouterId, Router);
    MkCheckErrorLog(ErrorCode, "dst id:%s not found\n", RouterId.c_str());
    return SendSipRequest(RouterId, DstId, Router.SipRealm, MkSipMethodMessage, Router.RemoteHost, Router.RemotePort, Router.bTcp, nullptr, MkMapString(), MkSipContentXml, strXml);
}

Uint32 CMkGb28181::XmlItemParse(const tinyxml2::XMLElement *pElement, MkMapString &MapParam)
{
    const tinyxml2::XMLElement *pNode = pElement->FirstChildElement();
    while (pNode) {
        if (nullptr != pNode->GetText()) {
            MkString strUtf8;
            CMkUtil::Gbk2Utf8(CMkUtil::SafeMkString(pNode->GetText()), strUtf8);
            MapParam[CMkUtil::SafeMkString(pNode->Name())] = strUtf8;
        }
        pNode = pNode->NextSiblingElement();
    }
    return NoneError;
}

Uint32 CMkGb28181::XmlToGbMessage(const tinyxml2::XMLElement *pElement, MkGbMessage& GbMessage)
{
    const tinyxml2::XMLElement *pOffsetElement = pElement;
    while (pOffsetElement) {
        if (!pOffsetElement->GetText()) {
            const tinyxml2::XMLElement *pChildElement = pOffsetElement->FirstChildElement();
            if ("Info" == CMkUtil::SafeMkString(pOffsetElement->Name())) {
                while (pChildElement) {
                    GbMessage.InfoParam.emplace_back(MkPair<MkString, MkString>(CMkUtil::SafeMkString(pChildElement->Name()), CMkUtil::SafeMkString(pChildElement->GetText())));
                    pChildElement = pChildElement->NextSiblingElement();
                }
            } else if ("SnapShotList" == CMkUtil::SafeMkString(pOffsetElement->Name())) {
                while (pChildElement) {
                    GbMessage.SnapShotParam.emplace_back(MkPair<MkString, MkString>(CMkUtil::SafeMkString(pChildElement->Name()), CMkUtil::SafeMkString(pChildElement->GetText())));
                    pChildElement = pChildElement->NextSiblingElement();
                }
            } else if (pOffsetElement->Attribute("Num")) {  //has attribute num
                if (pChildElement) {
                    GbMessage.ItemName = CMkUtil::SafeMkString(pChildElement->Name());
                }
                GbMessage.ChildKey = CMkUtil::SafeMkString(pOffsetElement->Name());
                while (pChildElement) {
                    MkGbMessage GbMsg;
                    XmlItemParse(pChildElement, GbMsg.MainParam);
                    if (!GbMsg.MainParam.empty()) {
                        GbMessage.VecChildren.emplace_back(GbMsg);
                    }
                    pChildElement = pChildElement->NextSiblingElement();
                }
            } else {
                MkGbMessage GbMsg;
                XmlToGbMessage(pChildElement, GbMsg);
                if (CMkUtil::SafeMkString(pOffsetElement->Name()) == GbMessage.ChildKey) {
                    GbMessage.VecChildren.emplace_back(GbMsg);
                } else {
                    MkMap<MkString, struct _gb_message>::iterator it = GbMessage.MapMessage.find(CMkUtil::SafeMkString(pOffsetElement->Name()));
                    if (it != GbMessage.MapMessage.end()) {
                        GbMessage.ChildKey = CMkUtil::SafeMkString(pOffsetElement->Name());
                        GbMessage.VecChildren.emplace_back(it->second);
                        GbMessage.VecChildren.emplace_back(GbMsg);
                        GbMessage.MapMessage.clear();
                    } else {
                        GbMessage.MapMessage[CMkUtil::SafeMkString(pOffsetElement->Name())] = GbMsg;
                    }
                }
            }
        } else {
            MkString strUtf8;
            CMkUtil::Gbk2Utf8(CMkUtil::SafeMkString(pOffsetElement->GetText()), strUtf8);
            GbMessage.MainParam[CMkUtil::SafeMkString(pOffsetElement->Name())] = strUtf8;
        }
        pOffsetElement = pOffsetElement->NextSiblingElement();
    }
    return NoneError;
}

Uint32 CMkGb28181::MapStringToXml(const MkMapString& MapParam, tinyxml2::XMLDocument& doc, tinyxml2::XMLElement *pParentElement)
{
    tinyxml2::XMLElement *ItemNode = nullptr;
    MkMapString::const_iterator itMap = MapParam.begin();
    for (; itMap != MapParam.end(); itMap++) {
        ItemNode = doc.NewElement(itMap->first.c_str());
        MkString strGbk;
        CMkUtil::Utf8ToGbk(itMap->second, strGbk);
        ItemNode->InsertFirstChild(doc.NewText(strGbk.c_str()));
        pParentElement->InsertEndChild(ItemNode);
    }
    return NoneError;
}

Uint32 CMkGb28181::GbMessageToXml(const MkGbMessage& GbMessage, tinyxml2::XMLDocument& doc, tinyxml2::XMLElement *pParentElement, Uint32 SumChild/* = 0*/)
{
    MapStringToXml(GbMessage.MainParam, doc, pParentElement);
    tinyxml2::XMLElement *ItemNode = nullptr;
    if (!GbMessage.ItemName.empty()) {
        MkVector<struct _gb_message>::const_iterator itChild = GbMessage.VecChildren.begin();
        if (GbMessage.ChildKey.empty()) {
            for (; itChild != GbMessage.VecChildren.end(); itChild++) {
                tinyxml2::XMLElement *pItemNode = doc.NewElement(GbMessage.ItemName.c_str());
                MapStringToXml(itChild->MainParam, doc, pItemNode);
                pParentElement->InsertEndChild(pItemNode);
            }
        } else {
            tinyxml2::XMLElement *pChildItem = doc.NewElement(GbMessage.ChildKey.c_str());
            pChildItem->SetAttribute("Num", static_cast<int>(GbMessage.VecChildren.size()));

            for (; itChild != GbMessage.VecChildren.end(); itChild++) {
                tinyxml2::XMLElement *pItemNode = doc.NewElement(GbMessage.ItemName.c_str());
                MapStringToXml(itChild->MainParam, doc, pItemNode);
                pChildItem->InsertEndChild(pItemNode);
            }
            pParentElement->InsertEndChild(pChildItem);
        }
    } else {
        MkVector<struct _gb_message>::const_iterator itChild = GbMessage.VecChildren.begin();
        for (; itChild != GbMessage.VecChildren.end(); itChild++) {
            tinyxml2::XMLElement *pChildNode = doc.NewElement(GbMessage.ChildKey.c_str());
            MapStringToXml(itChild->MainParam, doc, pChildNode);
            pParentElement->InsertEndChild(pChildNode);
        }
    }

    MkMap<MkString, struct _gb_message>::const_iterator itMap = GbMessage.MapMessage.begin();
    for (; itMap != GbMessage.MapMessage.end(); itMap++) {
        tinyxml2::XMLElement *pMapItem = doc.NewElement(itMap->first.c_str());
        GbMessageToXml(itMap->second, doc, pMapItem);
        pParentElement->InsertEndChild(pMapItem);
    }
    return NoneError;
}

Uint32 CMkGb28181::RequestCheck()
{
    MapRequest MapTmp;
    MapRequest::iterator itReq;
    m_RequestLock.Lock();
    itReq = m_MapRequest.begin();
    while (itReq != m_MapRequest.end()) {
        if (NowMkTime.OffsetSec(itReq->second.RequestTime) > static_cast<int>(m_RequestTimeOutSec)) {
            MapTmp[itReq->first] = itReq->second;
            itReq = m_MapRequest.erase(itReq);
        } else {
            itReq++;
        }
    }
    m_RequestLock.Unlock();
    itReq = MapTmp.begin();
    for (; itReq != MapTmp.end(); itReq++) {
        if (itReq->second.Cb) {
            itReq->second.Cb(MkSipStatusRequestTimeout + SipResponseErrorBegin, nullptr);
        }
    }
    return NoneError;
}

Uint32 CMkGb28181::AddRouter(const MkString& GbId, const MkString& GbRealm, const MkString& RemoteIp, Uint16 RemotePort, BOOL bTcp)
{
    MkGbRouter Router;
    Router.SipId = GbId;
    Router.SipRealm = GbRealm;
    Router.RemoteHost = RemoteIp;
    Router.RemotePort = RemotePort;
    Router.bTcp = bTcp;
    m_RouterLock.WLock();
    m_MapGbRouter[GbId] = Router;
    m_RouterLock.WUnlock();
    return NoneError;
}

Uint32 CMkGb28181::DeleteRouter(const MkString& GbId)
{
    Uint32 ErrorCode = InvalidId;
    m_RouterLock.WLock();
    MkMap<MkString, MkGbRouter>::iterator it = m_MapGbRouter.find(GbId);
    if (it != m_MapGbRouter.end()) {
        m_MapGbRouter.erase(it);
        ErrorCode = NoneError;
    }
    m_RouterLock.WUnlock();
    return ErrorCode;
}

Uint32 CMkGb28181::GetRouter(const MkString& GbId, MkGbRouter& Router)
{
    Uint32 ErrorCode = InvalidId;
    m_RouterLock.WLock();
    MkMap<MkString, MkGbRouter>::iterator it = m_MapGbRouter.find(GbId);
    if (it != m_MapGbRouter.end()) {
        Router = it->second;
        ErrorCode = NoneError;
    }
    m_RouterLock.WUnlock();
    return ErrorCode;
}

CMkGb28181::~CMkGb28181()
{
    Stop();
}
